﻿/******************************************************************************
 * GSearchPad.xaml.cs
 * 
 * This module implements the code-behind for the GSearchPad.xaml front-end.
 * 
 * Date:   12/2008
 * 
 * Copyright (c) 2009, Mark Betz 
 * 
 * All rights reserved. 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 * 
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 *   * Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution. 
 *   * Neither the name of the Author nor the names of contributors may be 
 *     used to endorse or promote products derived from this software
 *     without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY MARK BETZ ''AS IS'' AND ANY  EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL MARK BETZ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * 
 */
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using GSearch;

namespace GSearchPad
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWin : Window
    {
        public MainWin()
        {
            InitializeComponent();
        }
        
        /// <summary>
        /// Handles the 'Go' button click event, sends the event to the
        /// search engine for the current selected tab
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GoSearchButton_OnClick( object sender, EventArgs e )
        {
            switch( SearchTypeTabs.SelectedIndex )
            {
                case 0:
                    ExecWebSearch();
                    break;

                case 1:
                    ExecImageSearch();
                    break;

                case 2:
                    ExecVideoSearch();
                    break;
                    
                case 3:
                    ExecBookSearch();
                    break;
                    
                case 4:
                    ExecLocalSearch();
                    break;
                    
                case 5:
                    ExecBlogSearch();
                    break;
                    
                case 6:
                    ExecPatentSearch();
                    break;
                    
                case 7:
                    ExecNewsSearch();
                    break;
            }        
        }
        
        /// <summary>
        /// Handles the selection changed event on the tab control, opens the
        /// appropriate view
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SearchTypeTabs_SelectionChanged( object sender, SelectionChangedEventArgs e)
        {
            switch( SearchTypeTabs.SelectedIndex )
            {
                case 0:
                    OpenWebSearch();
                    break;
                    
                case 1:
                    OpenImageSearch();
                    break;
                    
                case 2:
                    OpenVideoSearch();
                    break;
                    
                case 3:
                    OpenBookSearch();
                    break;
                    
                case 4:
                    OpenLocalSearch();
                    break;
                    
                case 5:
                    OpenBlogSearch();
                    break;
                    
                case 6:
                    OpenPatentSearch();
                    break;

                case 7:
                    OpenNewsSearch();
                    break;
            }
            CheckGoButton();
        }
        
        /// <summary>
        /// Closes up all of the search-specific argument panels
        /// </summary>
        private void CloseArgPanels()
        {
            WebArgsPanel.Visibility = Visibility.Collapsed;
            ImageArgsPanel.Visibility = Visibility.Collapsed;
            VideoArgsPanel.Visibility = Visibility.Collapsed;
            LocalArgsPanel.Visibility = Visibility.Collapsed;
            BookArgsPanel.Visibility = Visibility.Collapsed;
            BlogArgsPanel.Visibility = Visibility.Collapsed;
            PatentArgsPanel.Visibility = Visibility.Collapsed;
            NewsArgsPanel.Visibility = Visibility.Collapsed;
        }
        
        /// <summary>
        /// Handles a TextChanged event on the SearchTermsEdit control, part of the
        /// mechanism that enables/disables the Go button when certain conditions
        /// are met
        /// </summary>
        /// <param name="sender">The TextBox (as object) that raised the event</param>
        /// <param name="e">Instance of <see cref="TextChangedEventArgs"/></param>
        private void SearchTermsEdit_TextChanged(object sender, TextChangedEventArgs e)
        {
            CheckGoButton();
        }
        
        /// <summary>
        /// CheckGoButton checks the conditions for enabling/disabling the Go button
        /// and takes the appropriate action. The code calls this method whenever the
        /// state of one of the monitored controls changes. This mechanism is in
        /// place to accomodate the News search type, which allows certain queries to
        /// execute without search terms.
        /// </summary>
        private void CheckGoButton()
        {
            if ( App.Current.Windows[0].IsLoaded )
            {
                if ((0 < SearchTermsEdit.Text.Length) || 
                   ((7 == SearchTypeTabs.SelectedIndex) && 
                    (0 < NewsSearchLocationEdit.Text.Length || 0 < NewsSearchQPIDEdit.Text.Length || 
                     SearchNewsTopics.All != (SearchNewsTopics)(NewsSearchTopicList.SelectedIndex))))
                    GoSearchButton.IsEnabled = true;
                else
                    GoSearchButton.IsEnabled = false;
            }
        }

        /// <summary>
        /// Handles the RequestNavigate event for the hyperlinks in the web
        /// results
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HyperLink_RequestNavigate(object sender, RoutedEventArgs e)
        {
            string navigateUri = ((Hyperlink)sender).NavigateUri.ToString();
            Process.Start(new ProcessStartInfo(navigateUri));
            e.Handled = true;
        }

#region Web Search Methods
        
        /// <summary>
        /// This method swaps the visibility of the web search status message
        /// and results listbox, and displays the string in msg if any
        /// </summary>
        /// <param name="msg"></param>
        private void SetWebResultsMsg( string msg )
        {
            if ( null != msg )
            {
                WebResultsMsg.Visibility = Visibility.Visible;
                WebResultsList.Visibility = Visibility.Collapsed;
                WebResultsMsg.Text = msg;
            }
            else
            {
                WebResultsMsg.Visibility = Visibility.Collapsed;
                WebResultsList.Visibility = Visibility.Visible;
                WebResultsMsg.Text = "";
            }
        }
        
        /// <summary>
        /// This method is called from the tab control selection changed event
        /// handler. It opens up the web search page by setting the status message based
        /// on whether there are results in the list. It then displays the web search
        /// arguments panel.
        /// </summary>
        private void OpenWebSearch()
        {
            CloseArgPanels();
            if ( true == WebResultsList.HasItems )
                SetWebResultsMsg(null);
            else
                SetWebResultsMsg("No results to display");                
            WebArgsPanel.Visibility = Visibility.Visible;
        }
        
        /// <summary>
        /// This method executes a web search based on the current set of search
        /// arguments and the passed start index. It is used to seek to one of
        /// the results pages.
        /// </summary>
        /// <param name="startIdx"></param>
        private void WebSearchToPage(int startIdx)
        {
            GWebSearch gws = new GWebSearch();
            gws.SearchFailed += new EventHandler<WebSearchEventArgs>(gws_SearchFailed);
            gws.SearchProgressChanged += new EventHandler<WebSearchEventArgs>(gws_SearchProgressChanged);
            
            _wsa.StartIndex = startIdx;
            
            try
            {
                gws.SearchAsync(_wsa);
                SetWebResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetWebResultsMsg("Error occured during search: " + ex.Message);
            }
        }
        
        /// <summary>
        /// This method starts a new web search. It creates the search engine and wires up
        /// events, then creates a new arguments object, and populates it from the ui panels.
        /// Finally, it executes the async search method of the engine.
        /// </summary>
        private void ExecWebSearch()
        {
            GWebSearch gws = new GWebSearch();
            gws.SearchFailed += new EventHandler<WebSearchEventArgs>(gws_SearchFailed);
            gws.SearchProgressChanged += new EventHandler<WebSearchEventArgs>(gws_SearchProgressChanged);

            _wsa = new WebSearchArgs();
            _wsa.Terms = SearchTermsEdit.Text;
            _wsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _wsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _wsa.ApiKey = ApiKeyEdit.Text;
            _wsa.Filter = (SearchSafety)WebSafeSearch.SelectedIndex;
            _wsa.ResultLang = (SearchResultLang)ResLangList.SelectedIndex;
            _wsa.CustomSearchId = CSEIdEdit.Text;
            _wsa.CustomSearchUrl = CSEUrlEdit.Text;
            
            try
            {
                gws.SearchAsync(_wsa);
                SetWebResultsMsg("Searching...");
            }
            catch( Exception ex )
            {
                SetWebResultsMsg("Error occured during search: " + ex.Message);        
            }
        }
        
        /// <summary>
        /// Handles the GWebSearch.SearchFailed event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gws_SearchFailed(object sender, WebSearchEventArgs e)
        {
            SetWebResultsMsg("Search failed: " + e.Ex.Message);
        }
        
        /// <summary>
        /// Handles GWebSearch.SearchProgressChanged events from the search
        /// engine, and updates the status message. When complete is recieved it
        /// sets the data context of the listbox and builds the pager control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gws_SearchProgressChanged(object sender, WebSearchEventArgs e)
        {
            switch( e.Status )
            {
                case SearchStatus.Connecting:
                    SetWebResultsMsg("Connecting...");
                    break;
                    
                case SearchStatus.ResultsReceived:
                    SetWebResultsMsg("Results received, parsing...");
                    break;
                    
                case SearchStatus.Complete:
                    if ( e.Result.Response.Results.Length > 0 )
                    {
                        WebResultsList.DataContext = e.Result.Response.Results;
                        WebResultsList.ScrollIntoView(WebResultsList.Items[0]);
                        SetWebResultsMsg(null);
                        BuildWebPager(e.Result.Response.Cursor);
                    }
                    else SetWebResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetWebResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }
                
        /// <summary>
        /// Builds the pager control at the bottom of the results list. The
        /// passed cursor is the one returned from the most recent search. It
        /// contains an array of GPages, that specify the page label and starting
        /// index. The starting index is a 0-based index of the search results. If
        /// the search specified a large result set then there are 8 results per
        /// page, otherwise there are 4. So in the former case page 1 starts at 0,
        /// page 2 at 8, etc. This method stores the starting index of the page
        /// in the Tag property of that page's label in the pager, so it is easy
        /// to retrieve it in the mouse click event for the label.
        /// </summary>
        /// <param name="cursor"></param>
        private void BuildWebPager(GCursor cursor)
        {
            WebResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            WebResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if ( page.Start != _wsa.StartIndex )
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(WebPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }    
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                WebResultsPager.Children.Add(lbl);
            }
            if ( WebResultsPager.Children.Count > 1 )
                WebResultsPager.Visibility = Visibility.Visible;
            else
                WebResultsPager.Visibility = Visibility.Collapsed;
        }
        
        /// <summary>
        /// Handles the MouseLeftButtonUpEvent for the pager labels
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            WebSearchToPage( Convert.ToInt32(((Label)sender).Tag));
        }
        
#endregion
#region Image Search Methods        

        private void SetImageResultsMsg(string msg)
        {
            if (null != msg)
            {
                ImageResultsMsg.Visibility = Visibility.Visible;
                ImageResultsList.Visibility = Visibility.Collapsed;
                ImageResultsMsg.Text = msg;
            }
            else
            {
                ImageResultsMsg.Visibility = Visibility.Collapsed;
                ImageResultsList.Visibility = Visibility.Visible;
                ImageResultsMsg.Text = "";
            }
        }

        private void OpenImageSearch()
        {
            CloseArgPanels();
            if (true == ImageResultsList.HasItems)
                SetImageResultsMsg(null);
            else
                SetImageResultsMsg("No results to display");
            ImageArgsPanel.Visibility = Visibility.Visible;
        }

        private void ImageSearchToPage(int startIdx)
        {
            GImageSearch gis = new GImageSearch();
            gis.SearchFailed += new EventHandler<ImageSearchEventArgs>(gis_SearchFailed);
            gis.SearchProgressChanged += new EventHandler<ImageSearchEventArgs>(gis_SearchProgressChanged);

            _isa.StartIndex = startIdx;

            try
            {
                gis.SearchAsync(_isa);
                SetImageResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetImageResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecImageSearch()
        {
            GImageSearch gis = new GImageSearch();
            gis.SearchFailed += new EventHandler<ImageSearchEventArgs>(gis_SearchFailed);
            gis.SearchProgressChanged += new EventHandler<ImageSearchEventArgs>(gis_SearchProgressChanged);

            _isa = new ImageSearchArgs();

            _isa.Terms = SearchTermsEdit.Text;
            _isa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _isa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _isa.ApiKey = ApiKeyEdit.Text;
            _isa.Filter = (SearchSafety)ImageSearchSafetyList.SelectedIndex;
            _isa.SearchDomain = ImageSearchDomainEdit.Text;
            _isa.ImageSize = (SearchImageSize)ImageSearchSizeList.SelectedIndex;
            _isa.Color = (SearchImageColor)ImageSearchColorList.SelectedIndex;
            _isa.ImageType = (SearchImageType)ImageSearchTypeList.SelectedIndex;
            _isa.FileType = (SearchImageFileType)ImageSearchFileTypeList.SelectedIndex;
            _isa.Restriction = (SearchImageRestrict)ImageSearchRestrictList.SelectedIndex;
            
            try
            {
                gis.SearchAsync(_isa);
                SetImageResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetImageResultsMsg("Error occured during search: " + ex.Message);
            }
        }
        
        private void gis_SearchFailed(object sender, ImageSearchEventArgs e)
        {
            SetImageResultsMsg("Search failed: " + e.Ex.Message);
        }
        
        private void gis_SearchProgressChanged(object sender, ImageSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetImageResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetImageResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if ( e.Result.Response.Results.Length > 0 )
                    {
                        ImageResultsList.DataContext = e.Result.Response.Results;
                        ImageResultsList.ScrollIntoView(ImageResultsList.Items[0]);
                        SetImageResultsMsg(null);
                        BuildImagePager(e.Result.Response.Cursor);
                    }
                    else SetImageResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetImageResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildImagePager(GCursor cursor)
        {
            ImageResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            ImageResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _isa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(ImagePager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                ImageResultsPager.Children.Add(lbl);
            }
            if (ImageResultsPager.Children.Count > 1)
                ImageResultsPager.Visibility = Visibility.Visible;
            else
                ImageResultsPager.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Handles the MouseLeftButtonUpEvent for the pager labels
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ImagePager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ImageSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }
        
#endregion
#region Video Search Methods

        private void SetVideoResultsMsg(string msg)
        {
            if (null != msg)
            {
                VideoResultsMsg.Visibility = Visibility.Visible;
                VideoResultsList.Visibility = Visibility.Collapsed;
                VideoResultsMsg.Text = msg;
            }
            else
            {
                VideoResultsMsg.Visibility = Visibility.Collapsed;
                VideoResultsList.Visibility = Visibility.Visible;
                VideoResultsMsg.Text = "";
            }
        }

        private void OpenVideoSearch()
        {
            CloseArgPanels();
            if (true == VideoResultsList.HasItems)
                SetVideoResultsMsg(null);
            else
                SetVideoResultsMsg("No results to display");
            VideoArgsPanel.Visibility = Visibility.Visible;
        }

        private void VideoSearchToPage(int startIdx)
        {
            GVideoSearch gvs = new GVideoSearch();
            gvs.SearchFailed += new EventHandler<VideoSearchEventArgs>(gvs_SearchFailed);
            gvs.SearchProgressChanged += new EventHandler<VideoSearchEventArgs>(gvs_SearchProgressChanged);

            _vsa.StartIndex = startIdx;

            try
            {
                gvs.SearchAsync(_vsa);
                SetVideoResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetVideoResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecVideoSearch()
        {
            GVideoSearch gvs = new GVideoSearch();
            gvs.SearchFailed += new EventHandler<VideoSearchEventArgs>(gvs_SearchFailed);
            gvs.SearchProgressChanged += new EventHandler<VideoSearchEventArgs>(gvs_SearchProgressChanged);

            _vsa = new VideoSearchArgs();

            _vsa.Terms = SearchTermsEdit.Text;
            _vsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _vsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _vsa.ApiKey = ApiKeyEdit.Text;
            _vsa.VideoScoring = (SearchScoring)VideoSearchScoringList.SelectedIndex;

            try
            {
                gvs.SearchAsync(_vsa);
                SetVideoResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetVideoResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gvs_SearchFailed(object sender, VideoSearchEventArgs e)
        {
            SetVideoResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gvs_SearchProgressChanged(object sender, VideoSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetVideoResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetVideoResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if ( e.Result.Response.Results.Length > 0 )
                    {
                        VideoResultsList.DataContext = e.Result.Response.Results;
                        VideoResultsList.ScrollIntoView(VideoResultsList.Items[0]);
                        SetVideoResultsMsg(null);
                        BuildVideoPager(e.Result.Response.Cursor);
                    }
                    else SetVideoResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetImageResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildVideoPager(GCursor cursor)
        {
            VideoResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            VideoResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _vsa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(VideoPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                VideoResultsPager.Children.Add(lbl);
            }
            if (VideoResultsPager.Children.Count > 1)
                VideoResultsPager.Visibility = Visibility.Visible;
            else
                VideoResultsPager.Visibility = Visibility.Collapsed;
        }

        private void VideoPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            VideoSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }

#endregion
#region Book Search Methods

        private void SetBookResultsMsg(string msg)
        {
            if (null != msg)
            {
                BookResultsMsg.Visibility = Visibility.Visible;
                BookResultsList.Visibility = Visibility.Collapsed;
                BookResultsMsg.Text = msg;
            }
            else
            {
                BookResultsMsg.Visibility = Visibility.Collapsed;
                BookResultsList.Visibility = Visibility.Visible;
                BookResultsMsg.Text = "";
            }
        }

        private void OpenBookSearch()
        {
            CloseArgPanels();
            if (true == BookResultsList.HasItems)
                SetBookResultsMsg(null);
            else
                SetBookResultsMsg("No results to display");
            BookArgsPanel.Visibility = Visibility.Visible;
        }

        private void BookSearchToPage(int startIdx)
        {
            GBookSearch gbs = new GBookSearch();
            gbs.SearchFailed += new EventHandler<BookSearchEventArgs>(gbs_SearchFailed);
            gbs.SearchProgressChanged += new EventHandler<BookSearchEventArgs>(gbs_SearchProgressChanged);

            _bsa.StartIndex = startIdx;

            try
            {
                gbs.SearchAsync(_bsa);
                SetBookResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetBookResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecBookSearch()
        {
            GBookSearch gbs = new GBookSearch();
            gbs.SearchFailed += new EventHandler<BookSearchEventArgs>(gbs_SearchFailed);
            gbs.SearchProgressChanged += new EventHandler<BookSearchEventArgs>(gbs_SearchProgressChanged);

            _bsa = new BookSearchArgs();

            _bsa.Terms = SearchTermsEdit.Text;
            _bsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _bsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _bsa.ApiKey = ApiKeyEdit.Text;
            _bsa.BookTypes = (SearchBookViewTypes)BookViewTypesList.SelectedIndex;

            try
            {
                gbs.SearchAsync(_bsa);
                SetBookResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetBookResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gbs_SearchFailed(object sender, BookSearchEventArgs e)
        {
            SetBookResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gbs_SearchProgressChanged(object sender, BookSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetBookResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetBookResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if ( e.Result.Response.Results.Length > 0 )
                    {
                        BookResultsList.DataContext = e.Result.Response.Results;
                        BookResultsList.ScrollIntoView(BookResultsList.Items[0]);
                        SetBookResultsMsg(null);
                        BuildBookPager(e.Result.Response.Cursor);
                    }
                    else SetBookResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetBookResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildBookPager(GCursor cursor)
        {
            BookResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            BookResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _bsa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(BookPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                BookResultsPager.Children.Add(lbl);
            }
            if (BookResultsPager.Children.Count > 1)
                BookResultsPager.Visibility = Visibility.Visible;
            else
                BookResultsPager.Visibility = Visibility.Collapsed;
        }

        private void BookPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            BookSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }

#endregion
#region Local Search Methods

        private void SetLocalResultsMsg(string msg)
        {
            if (null != msg)
            {
                LocalResultsMsg.Visibility = Visibility.Visible;
                LocalResultsList.Visibility = Visibility.Collapsed;
                LocalResultsMsg.Text = msg;
            }
            else
            {
                LocalResultsMsg.Visibility = Visibility.Collapsed;
                LocalResultsList.Visibility = Visibility.Visible;
                LocalResultsMsg.Text = "";
            }
        }

        private void OpenLocalSearch()
        {
            CloseArgPanels();
            if (true == LocalResultsList.HasItems)
                SetLocalResultsMsg(null);
            else
                SetLocalResultsMsg("No results to display");
            LocalArgsPanel.Visibility = Visibility.Visible;
        }

        private void LocalSearchToPage(int startIdx)
        {
            GLocalSearch gls = new GLocalSearch();
            gls.SearchFailed += new EventHandler<LocalSearchEventArgs>(gls_SearchFailed);
            gls.SearchProgressChanged += new EventHandler<LocalSearchEventArgs>(gls_SearchProgressChanged);

            _lsa.StartIndex = startIdx;

            try
            {
                gls.SearchAsync(_lsa);
                SetLocalResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetLocalResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecLocalSearch()
        {
            GLocalSearch gls = new GLocalSearch();
            gls.SearchFailed += new EventHandler<LocalSearchEventArgs>(gls_SearchFailed);
            gls.SearchProgressChanged += new EventHandler<LocalSearchEventArgs>(gls_SearchProgressChanged);

            _lsa = new LocalSearchArgs();

            _lsa.Terms = SearchTermsEdit.Text;
            _lsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _lsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _lsa.ApiKey = ApiKeyEdit.Text;

            if ( SCLatEdit.Text.Length > 0 && SCLngEdit.Text.Length > 0 )
            {
                _lsa.SearchCenter = new Coordinate();
                try
                {
                    _lsa.SearchCenter.Latitude = Convert.ToDouble(SCLatEdit.Text);
                }
                catch(Exception)
                {
                    SetLocalResultsMsg("Invalid value for Search Center lattitude");
                    SCLatEdit.Text = "";
                    return;
                }

                try
                {
                    _lsa.SearchCenter.Longitude = Convert.ToDouble(SCLngEdit.Text);
                }
                catch (Exception)
                {
                    SetLocalResultsMsg("Invalid value for Search Center longitude");
                    SCLngEdit.Text = "";
                    return;
                }
            }

            if (BB1Edit.Text.Length > 0 && BB2Edit.Text.Length > 0)
            {
                _lsa.Bounding = new BoundingRect();
                try
                {
                    _lsa.Bounding.Term1 = Convert.ToDouble(BB1Edit.Text);
                }
                catch (Exception)
                {
                    SetLocalResultsMsg("Invalid value for Bounding Box term 1");
                    BB1Edit.Text = "";
                    return;
                }

                try
                {
                    _lsa.Bounding.Term2 = Convert.ToDouble(BB2Edit.Text);
                }
                catch (Exception)
                {
                    SetLocalResultsMsg("Invalid value for Bounding Box term 2");
                    BB2Edit.Text = "";
                    return;
                }
            }
            
            _lsa.Results = (SearchLocalResults)LocalResultTypesList.SelectedIndex;

            try
            {
                gls.SearchAsync(_lsa);
                SetLocalResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetLocalResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gls_SearchFailed(object sender, LocalSearchEventArgs e)
        {
            SetLocalResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gls_SearchProgressChanged(object sender, LocalSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetLocalResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetLocalResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if ( e.Result.Response.Results.Length > 0 )
                    {
                        LocalResultsList.DataContext = e.Result.Response.Results;
                        LocalResultsList.ScrollIntoView(LocalResultsList.Items[0]);
                        SetLocalResultsMsg(null);
                        BuildLocalPager(e.Result.Response.Cursor);
                    }
                    else SetLocalResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetLocalResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildLocalPager(GCursor cursor)
        {
            LocalResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            LocalResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _lsa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(LocalPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                LocalResultsPager.Children.Add(lbl);
            }
            if (LocalResultsPager.Children.Count > 1)
                LocalResultsPager.Visibility = Visibility.Visible;
            else
                LocalResultsPager.Visibility = Visibility.Collapsed;
        }

        private void LocalPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            LocalSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }

#endregion
#region Blog Search Methods

        private void SetBlogResultsMsg(string msg)
        {
            if (null != msg)
            {
                BlogResultsMsg.Visibility = Visibility.Visible;
                BlogResultsList.Visibility = Visibility.Collapsed;
                BlogResultsMsg.Text = msg;
            }
            else
            {
                BlogResultsMsg.Visibility = Visibility.Collapsed;
                BlogResultsList.Visibility = Visibility.Visible;
                BlogResultsMsg.Text = "";
            }
        }

        private void OpenBlogSearch()
        {
            CloseArgPanels();
            if (true == BlogResultsList.HasItems)
                SetBlogResultsMsg(null);
            else
                SetBlogResultsMsg("No results to display");
            BlogArgsPanel.Visibility = Visibility.Visible;
        }

        private void BlogSearchToPage(int startIdx)
        {
            GBlogSearch gbls = new GBlogSearch();
            gbls.SearchFailed += new EventHandler<BlogSearchEventArgs>(gbls_SearchFailed);
            gbls.SearchProgressChanged += new EventHandler<BlogSearchEventArgs>(gbls_SearchProgressChanged);

            _blsa.StartIndex = startIdx;

            try
            {
                gbls.SearchAsync(_blsa);
                SetBlogResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetBlogResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecBlogSearch()
        {
            GBlogSearch gbls = new GBlogSearch();
            gbls.SearchFailed += new EventHandler<BlogSearchEventArgs>(gbls_SearchFailed);
            gbls.SearchProgressChanged += new EventHandler<BlogSearchEventArgs>(gbls_SearchProgressChanged);

            _blsa = new BlogSearchArgs();

            _blsa.Terms = SearchTermsEdit.Text;
            _blsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _blsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _blsa.ApiKey = ApiKeyEdit.Text;

            _blsa.Scoring = (SearchScoring)BlogSearchScoringList.SelectedIndex;

            try
            {
                gbls.SearchAsync(_blsa);
                SetBlogResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetBlogResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gbls_SearchFailed(object sender, BlogSearchEventArgs e)
        {
            SetBlogResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gbls_SearchProgressChanged(object sender, BlogSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetBlogResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetBlogResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if (e.Result.Response.Results.Length > 0)
                    {
                        BlogResultsList.DataContext = e.Result.Response.Results;
                        BlogResultsList.ScrollIntoView(BlogResultsList.Items[0]);
                        SetBlogResultsMsg(null);
                        BuildBlogPager(e.Result.Response.Cursor);
                    }
                    else SetBlogResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetBlogResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildBlogPager(GCursor cursor)
        {
            BlogResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            BlogResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _blsa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(BlogPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                BlogResultsPager.Children.Add(lbl);
            }
            if (BlogResultsPager.Children.Count > 1)
                BlogResultsPager.Visibility = Visibility.Visible;
            else
                BlogResultsPager.Visibility = Visibility.Collapsed;
        }

        private void BlogPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            BlogSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }

#endregion
#region Patent Search Methods

        private void SetPatentResultsMsg(string msg)
        {
            if (null != msg)
            {
                PatentResultsMsg.Visibility = Visibility.Visible;
                PatentResultsList.Visibility = Visibility.Collapsed;
                PatentResultsMsg.Text = msg;
            }
            else
            {
                PatentResultsMsg.Visibility = Visibility.Collapsed;
                PatentResultsList.Visibility = Visibility.Visible;
                PatentResultsMsg.Text = "";
            }
        }

        private void OpenPatentSearch()
        {
            CloseArgPanels();
            if (true == PatentResultsList.HasItems)
                SetPatentResultsMsg(null);
            else
                SetPatentResultsMsg("No results to display");
            PatentArgsPanel.Visibility = Visibility.Visible;
        }

        private void PatentSearchToPage(int startIdx)
        {
            GPatentSearch gps = new GPatentSearch();
            gps.SearchFailed += new EventHandler<PatentSearchEventArgs>(gps_SearchFailed);
            gps.SearchProgressChanged += new EventHandler<PatentSearchEventArgs>(gps_SearchProgressChanged);

            _psa.StartIndex = startIdx;

            try
            {
                gps.SearchAsync(_psa);
                SetPatentResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetPatentResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecPatentSearch()
        {
            GPatentSearch gps = new GPatentSearch();
            gps.SearchFailed += new EventHandler<PatentSearchEventArgs>(gps_SearchFailed);
            gps.SearchProgressChanged += new EventHandler<PatentSearchEventArgs>(gps_SearchProgressChanged);

            _psa = new PatentSearchArgs();

            _psa.Terms = SearchTermsEdit.Text;
            _psa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _psa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _psa.ApiKey = ApiKeyEdit.Text;

            _psa.Scoring = (SearchScoring)PatentSearchScoringList.SelectedIndex;
            _psa.Types = (SearchPatentStatus)PatentSearchStatusList.SelectedIndex;

            try
            {
                gps.SearchAsync(_psa);
                SetPatentResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetPatentResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gps_SearchFailed(object sender, PatentSearchEventArgs e)
        {
            SetPatentResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gps_SearchProgressChanged(object sender, PatentSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetPatentResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetPatentResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if (e.Result.Response.Results.Length > 0)
                    {
                        PatentResultsList.DataContext = e.Result.Response.Results;
                        PatentResultsList.ScrollIntoView(PatentResultsList.Items[0]);
                        SetPatentResultsMsg(null);
                        BuildPatentPager(e.Result.Response.Cursor);
                    }
                    else SetPatentResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetPatentResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildPatentPager(GCursor cursor)
        {
            PatentResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            PatentResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _psa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(PatentPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                PatentResultsPager.Children.Add(lbl);
            }
            if (PatentResultsPager.Children.Count > 1)
                PatentResultsPager.Visibility = Visibility.Visible;
            else
                PatentResultsPager.Visibility = Visibility.Collapsed;
        }

        private void PatentPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            PatentSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }

#endregion
#region News Search Methods

        private void SetNewsResultsMsg(string msg)
        {
            if (null != msg)
            {
                NewsResultsMsg.Visibility = Visibility.Visible;
                NewsResultsList.Visibility = Visibility.Collapsed;
                NewsResultsMsg.Text = msg;
            }
            else
            {
                NewsResultsMsg.Visibility = Visibility.Collapsed;
                NewsResultsList.Visibility = Visibility.Visible;
                NewsResultsMsg.Text = "";
            }
        }

        private void OpenNewsSearch()
        {
            CloseArgPanels();
            if (true == NewsResultsList.HasItems)
                SetNewsResultsMsg(null);
            else
                SetNewsResultsMsg("No results to display");
            NewsArgsPanel.Visibility = Visibility.Visible;
        }

        private void NewsSearchToPage(int startIdx)
        {
            GNewsSearch gns = new GNewsSearch();
            gns.SearchFailed += new EventHandler<NewsSearchEventArgs>(gns_SearchFailed);
            gns.SearchProgressChanged += new EventHandler<NewsSearchEventArgs>(gns_SearchProgressChanged);

            _nsa.StartIndex = startIdx;

            try
            {
                gns.SearchAsync(_nsa);
                SetNewsResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetNewsResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void ExecNewsSearch()
        {
            GNewsSearch gns = new GNewsSearch();
            gns.SearchFailed += new EventHandler<NewsSearchEventArgs>(gns_SearchFailed);
            gns.SearchProgressChanged += new EventHandler<NewsSearchEventArgs>(gns_SearchProgressChanged);

            _nsa = new NewsSearchArgs();

            _nsa.Terms = SearchTermsEdit.Text;
            _nsa.HostLang = (SearchHostLang)HostLangList.SelectedIndex;
            _nsa.ResultSize = (SearchResultSize)ResultSize.SelectedIndex;
            _nsa.ApiKey = ApiKeyEdit.Text;

            _nsa.Scoring = (SearchScoring)NewsSearchScoringList.SelectedIndex;
            _nsa.Location = NewsSearchLocationEdit.Text;
            _nsa.QuotedPersonId = NewsSearchQPIDEdit.Text;
            _nsa.Topic = (SearchNewsTopics)NewsSearchTopicList.SelectedIndex;
            _nsa.Edition = (SearchNewsEdition)NewsSearchEditionList.SelectedIndex;

            try
            {
                gns.SearchAsync(_nsa);
                SetNewsResultsMsg("Searching...");
            }
            catch (Exception ex)
            {
                SetNewsResultsMsg("Error occured during search: " + ex.Message);
            }
        }

        private void gns_SearchFailed(object sender, NewsSearchEventArgs e)
        {
            SetNewsResultsMsg("Search failed: " + e.Ex.Message);
        }

        private void gns_SearchProgressChanged(object sender, NewsSearchEventArgs e)
        {
            switch (e.Status)
            {
                case SearchStatus.Connecting:
                    SetNewsResultsMsg("Connecting...");
                    break;

                case SearchStatus.ResultsReceived:
                    SetNewsResultsMsg("Results received, parsing...");
                    break;

                case SearchStatus.Complete:
                    if (e.Result.Response.Results.Length > 0)
                    {
                        NewsResultsList.DataContext = e.Result.Response.Results;
                        NewsResultsList.ScrollIntoView(NewsResultsList.Items[0]);
                        SetNewsResultsMsg(null);
                        BuildNewsPager(e.Result.Response.Cursor);
                    }
                    else SetNewsResultsMsg("Your search did not produce any results");
                    break;

                case SearchStatus.Error:
                    SetNewsResultsMsg("Error occured during search: " + e.Ex.Message);
                    break;
            }
        }

        private void BuildNewsPager(GCursor cursor)
        {
            NewsResultsPager.Children.Clear();
            Label lbl = new Label();
            lbl.Content = "Pages:";
            NewsResultsPager.Children.Add(lbl);
            foreach (GPage page in cursor.Pages)
            {
                lbl = new Label();
                lbl.Content = page.Label;
                lbl.Tag = page.Start;
                if (page.Start != _nsa.StartIndex)
                {
                    lbl.MouseLeftButtonUp += new MouseButtonEventHandler(NewsPager_MouseLeftButtonUp);
                    lbl.Cursor = Cursors.Hand;
                }
                else
                {
                    lbl.Foreground = new SolidColorBrush(Colors.Gray);
                    lbl.FontWeight = FontWeights.Bold;
                }
                NewsResultsPager.Children.Add(lbl);
            }
            if (NewsResultsPager.Children.Count > 1)
                NewsResultsPager.Visibility = Visibility.Visible;
            else
                NewsResultsPager.Visibility = Visibility.Collapsed;
        }

        private void NewsPager_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            NewsSearchToPage(Convert.ToInt32(((Label)sender).Tag));
        }
        
        private void NewsSearchLocationEdit_TextChanged(object sender, TextChangedEventArgs e)
        {
            CheckGoButton();
        }
        
        private void NewsSearchQPIDEdit_TextChanged(object sender, TextChangedEventArgs e)
        {
            CheckGoButton();
        }
        
        private void NewsSearchTopicList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            CheckGoButton();
        }

#endregion
        
        private WebSearchArgs _wsa;
        private ImageSearchArgs _isa;
        private VideoSearchArgs _vsa;
        private BookSearchArgs _bsa;
        private LocalSearchArgs _lsa;
        private BlogSearchArgs _blsa;
        private PatentSearchArgs _psa;
        private NewsSearchArgs _nsa;

    }
}
